/*
 * Copyright (c) 2020, yifengling0. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. No personal names or organizations' names associated with the
 *    Atomthreads project may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */


#include "pin.h"
#include "kassert.h"
#include "console.h"
#include "numberical.h"
#include <string.h>
#include "debug.h"


static Pin _hwPin;

void PinMode(int pin, int mode)
{
    _hwPin.Protected.ops->mode(&_hwPin, pin, mode);
}

void PinWrite(int pin, int value)
{
   _hwPin.Protected.ops->write(&_hwPin, pin, value);
}

int  PinRead(int pin)
{
    return _hwPin.Protected.ops->read(&_hwPin, pin);
}

void  PinToggle(int pin)
{
    _hwPin.Protected.ops->toggle(&_hwPin, pin);
}

static int pin_read(FD fd, char* buffer, size_t maxbytes)
{
    struct pin_status *status = (struct pin_status*)buffer;

    struct Pin* dev = (Pin*)fd;

    return dev->Protected.ops->read(dev, status->pin);
}

static int pin_write(FD fd, const char* buffer, size_t nbytes)
{
    struct pin_status *status = (struct pin_status*)buffer;

    struct Pin* dev = (Pin*)fd;

    dev->Protected.ops->write(dev, status->pin, status->status);
    
    return nbytes;
}

static int pin_ioctl(FD fd, int function, void* arg)
{
    struct Pin* dev = (Pin*)fd;
    struct pin_status *status = (struct pin_status*)arg;

    dev->Protected.ops->mode(dev, status->pin, status->status);

    return (OK);
}

#if defined(COM_USE_CONSOLE) && defined(COM_USE_PIN_CMD)

static enConsoleResult pin_probe(int argc, char **argv)
{
    enConsoleResult ret = CE_OK;
    
    if( strcmp(argv[1], "mode") == 0 && argc == 4){
        int pin = StringToInt(argv[2]);
        int mode = StringToInt(argv[3]);
        PinMode(pin, mode);
    }else if( strcmp(argv[1], "set") == 0 && argc == 4){
        int pin = StringToInt(argv[2]);
        int value = StringToInt(argv[3]);
        PinWrite(pin, value);
    }else if( strcmp(argv[1], "get") == 0 && argc == 3){
        int pin = StringToInt(argv[2]);
        KPrint(PinRead(pin) > 0 ? "1":"0");
    }else{
        ret = CE_PARAM_ERROR;
    }
    

    return (ret);
}

BGEIN_DEF_CMD(_pinCmd)
    CMD_DEF_ALISA(pin, pin_probe, "pin mode [no] [value]|get [no]|set [no] [value]")
END_DEF_CMD(_rtcCmd)

#endif

void PinCreate(const char*name, const struct PinOps *ops)
{
	_hwPin.super.pioctl = pin_ioctl;
	_hwPin.super.pread = pin_read;
	_hwPin.super.pwrite = pin_write;

    _hwPin.Protected.ops = ops;

#if defined(COM_USE_CONSOLE) && defined(COM_USE_PIN_CMD)
    CONSOLE_REG_CMD(_pinCmd);
#endif    
    
    IosDrvInstall(&_hwPin.super, name);
}